package cn.wgx.common.handler;

import cn.wgx.common.util.StringUtils;
import com.alibaba.fastjson.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.naming.NoPermissionException;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.lang.reflect.UndeclaredThrowableException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import static cn.wgx.common.util.ResponseDataUtil.getInitMap;
import static cn.wgx.common.util.ResponseDataUtil.returnErrorMap;

/**
 * @author
 * @version
 */
@RestControllerAdvice
public class ExceptionHandlerAdvice {

	private Logger logger = LoggerFactory.getLogger(getClass());

	@ExceptionHandler(value = Exception.class)
	private Map<String,Object> exceptionHandler(Exception e){
		Map<String,Object> map = getInitMap();
		if(e instanceof NoPermissionException){
			returnErrorMap(e.getMessage() == null?"无权访问此接口.":e.getMessage(), map);
		}else if(e instanceof UndeclaredThrowableException){
			UndeclaredThrowableException ee = (UndeclaredThrowableException)e;
			String message = ee.getUndeclaredThrowable().getMessage();
			returnErrorMap(message == null?"数据错误或数据超出长度限制.":message, map);
		}else if(e instanceof DataAccessException){
			returnErrorMap("数据错误或数据超出长度限制.", map);
		}else if(e instanceof SQLException){
			returnErrorMap("数据库错误.", map);}
		else if(e instanceof JSONException){
			returnErrorMap("JSON解析错误. ", map); }
		else if(e instanceof HttpMessageNotReadableException){
			returnErrorMap("请求体参数错误. json解析失败.", map);
		}else if(e instanceof MethodArgumentTypeMismatchException){
			returnErrorMap( "参数类型错误. ", map);
		}else if(e instanceof ServletRequestBindingException){
			returnErrorMap("缺少参数:  " + e.getMessage(), map);
		}else if(e instanceof OAuth2Exception){
			returnErrorMap("oauth2错误:  " + e.getMessage(), map);
		}else if(e instanceof ConstraintViolationException){
			ConstraintViolationException ee = (ConstraintViolationException)e;
			StringBuffer sb = new StringBuffer();
			ee.getConstraintViolations().forEach((s) -> {
				sb.append(s.getMessage()).append(",");
			});
			returnErrorMap( ee.getMessage(), map);
		}else if(e instanceof MethodArgumentNotValidException){
			MethodArgumentNotValidException ee = (MethodArgumentNotValidException)e;
			StringBuffer sb = new StringBuffer();
			List<FieldError> allErrors = ee.getBindingResult().getFieldErrors();
			allErrors.forEach((s) -> {
				sb.append("[");
				sb.append(s.getField());
				sb.append("]");
				sb.append(s.getDefaultMessage()).append(",");
			});
			returnErrorMap(sb.toString(), map);
		}else if(e instanceof RuntimeException){
			returnErrorMap( "系统错误或参数有误,请调整后再试", map);
			logger.error("RuntimeException : -> {}", StringUtils.join(e.getStackTrace()));
		}else{
			returnErrorMap( "系统内部问题,请稍后再试.", map);
			logger.error("other error: -> {}", StringUtils.join(e.getStackTrace()));
		}
		if(logger.isDebugEnabled()){
			//未知的错误
			e.printStackTrace();
			map.put("debug", e.getMessage());
			//map.put("debug2", StringUtils.join(e.getStackTrace()));
			logger.debug(e.getMessage());
		}
		return map;
	}


	@ExceptionHandler(value = DuplicateKeyException.class)
	private Map<String,Object> duplicateExceptionHandler(DuplicateKeyException e){
		String errMsg = e.getMessage();
		if(errMsg.contains("username")){
			return returnErrorMap("用户名已被占用.");
		}else{
			return returnErrorMap("duplicate error.");
		}
	}
}
